package client.controller;

import client.Protocal.ClientSocket;
import client.cell.FriendCell;
import client.cell.GroupCell;
import client.dialog.*;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import common.EnvelopeMessage;
import common.bodies.*;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;

import java.awt.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.List;
import java.util.*;
import java.util.function.Consumer;

public class MainController {
    private static final int CHUNK_SIZE = 1024 * 1024;
    private final Map<String, VBox> chatHistories = new HashMap<>();
    public StackPane mainContentArea;
    public Button loginOutBtn;
    public VBox notificationView;
    public ListView<NotificationBody> notificationList;
    public Button notificationToggleBtn;
    @FXML
    private VBox friendListView;
    @FXML
    private VBox groupListView;
    @FXML
    private VBox chatView;
    @FXML
    private VBox searchView;
    @FXML
    private Label chatTitle;
    @FXML
    private Label searchTitle;
    @FXML
    private ListView<FriendShipBody> friendList;
    @FXML
    private ListView<GroupShipBody> groupList;
    @FXML
    private ListView<Object> searchResultList;
    @FXML
    private TextField inputField;
    @FXML
    private TextField searchInputField;
    @FXML
    private VBox messageContainer;
    @FXML
    private Button friendToggleBtn;
    @FXML
    private Button groupToggleBtn;
    @FXML
    private Button friendSearchBtn;
    @FXML
    private Button groupSearchBtn;
    @FXML
    private Button addFriendBtn;
    @FXML
    private Button createGroupBtn;
    private UserBody user;
    private String currentChatTarget;
    private boolean isCurrentChatGroup = false;
    private ClientSocket clientSocket;
    private String searchMode;
    private List<String> mutedMembers = new ArrayList<>();

    private Consumer<List<String>> muteMembersCallback;

    public void setClientSocket(ClientSocket clientSocket) {
        this.clientSocket = clientSocket;
        initMessageListener();
    }

    public void setUser(UserBody user) {
        this.user = user;
    }

    @FXML
    public void initialize() {
        initFriendList();
        initGroupList();
        initSearchResultList();
        initNotificationList();


        inputField.setOnAction(event -> onSendMessage());

        searchInputField.setOnAction(event -> {
            sendSearchRequest(searchInputField.getText().trim());
        });

    }

    private void initFriendList() {
        friendList.setCellFactory(list -> {
            FriendCell cell = new FriendCell(user);

            cell.setOnFriendActionListener(new FriendCell.OnFriendActionListener() {

                public void onClick(FriendShipBody friend) {
                    groupList.getSelectionModel().clearSelection();
                    switchConversation(friend, false);
                }

                public void onDelete(FriendShipBody friend) {
                    if (ConfirmDialog.show("删除好友", "确定要删除该好友吗？")) {
                        System.out.println("删除好友: " + friend);
                        JSONObject object = new JSONObject();
                        object.put("friendship", friend);
                        EnvelopeMessage request = new EnvelopeMessage("friend", "delete", object);
                        clientSocket.send(request);
                        friendList.getItems().remove(friend);
                    }
                }


                public void onBlock(FriendShipBody friend) {
                    if (ConfirmDialog.show("拉黑好友", "确定要拉黑该好友吗？")) {
                        System.out.println("拉黑好友: " + friend);
                        JSONObject object = new JSONObject();
                        object.put("fromId", user.getId());
                        object.put("fromName", user.getName());
                        object.put("friendship", friend);
                        EnvelopeMessage request = new EnvelopeMessage("friend", "block", object);
                        clientSocket.send(request);
                        friendList.getItems().remove(friend);
                    }
                }


//                public void onClearHistory(FriendShipBody friend) {
//                    if (ConfirmDialog.show("清空聊天记录", "确定要清空聊天记录吗？")) {
//
//                        System.out.println("️ 清空聊天记录: " + friend);
//                    }
//                }
            });

            return cell;
        });
    }

    private void initGroupList() {
        groupList.setCellFactory(param -> {
            GroupCell cell = new GroupCell(user);

            cell.setOnClickGroup(group -> {
                friendList.getSelectionModel().clearSelection();
                switchConversation(group);
            });

            cell.setOnInviteFriend(group -> {
                System.out.println("邀请好友进群: " + group.getGroupName());
                List<FriendShipBody> allFriends = friendList.getItems();
                InviteFriendDialog.show(allFriends, group.getMemberNames(), user, invitedFriends -> {
                    JSONObject body = new JSONObject();
                    body.put("list", invitedFriends);
                    body.put("groupName", group.getGroupName());
                    body.put("groupId", group.getGroupId());
                    EnvelopeMessage request = new EnvelopeMessage("group", "invite", body);
                    clientSocket.send(request);
                });
            });

            cell.setOnQuitGroup(group -> {
                System.out.println("退出群聊: " + group.getGroupId());
                JSONObject object = new JSONObject();
                object.put("groupId", group.getGroupId());
                object.put("userId", user.getId());
                object.put("groupName", group.getGroupName());
                EnvelopeMessage request = new EnvelopeMessage("group", "quit", object);
                clientSocket.send(request);
                JSONObject body = new JSONObject();
                body.put("userId", user.getId());
                EnvelopeMessage groupReq = new EnvelopeMessage("group", "list", body);
                clientSocket.send(groupReq);
            });

            cell.setOnDismissGroup(group -> {
                System.out.println("解散群聊: " + group.getGroupName());
                JSONObject object = new JSONObject();
                object.put("groupId", group.getGroupId());
                object.put("groupName", group.getGroupName());
                object.put("managerId", user.getId());
                EnvelopeMessage request = new EnvelopeMessage("group", "disband", object);
                clientSocket.send(request);
                JSONObject body = new JSONObject();
                body.put("userId", user.getId());
                EnvelopeMessage groupReq = new EnvelopeMessage("group", "list", body);
                clientSocket.send(groupReq);
            });

            cell.setOnKickMember(group -> {
                System.out.println("踢人出群: " + group.getGroupName());
                List<String> groupMembers = group.getMemberNames();
                groupMembers.remove(user.getName());
                boolean confirmed = ConfirmDialog.show("确认操作", "你确定要踢人出群吗？");
                if (confirmed) {
                    KickMemberDialog.show(groupMembers, kickedMembers -> {
                        JSONObject object = new JSONObject();
                        object.put("groupId", group.getGroupId());
                        object.put("kickedMembers", kickedMembers);
                        object.put("userId", user.getId());
                        object.put("groupName", group.getGroupName());
                        EnvelopeMessage request = new EnvelopeMessage("group", "kick", object);
                        clientSocket.send(request);
                    });
                }
            });

            cell.setOnMuteManage(group -> {
                System.out.println("禁言管理" + group.getGroupName());
                List<String> groupMembers = group.getMemberNames();
                groupMembers.remove(user.getName());
                getMuteMembers(group.getGroupId(),mutedList -> {
                    MuteMemberDialog.show(groupMembers, mutedMembers, (memberName, isMuted) -> {
                        JSONObject object = new JSONObject();
                        object.put("groupId", group.getGroupId());
                        object.put("memberName", memberName);
                        object.put("groupName", group.getGroupName());
                        object.put("muted", isMuted);
                        clientSocket.send(new EnvelopeMessage("group", "mute", object));
                    });
                });
            });

            return cell;
        });

        groupList.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) -> {
            if (newVal != null) {
                friendList.getSelectionModel().clearSelection();
                switchConversation(newVal);
            }
        });
    }

    private void getMuteMembers(Integer groupId, Consumer<List<String>> callback) {
        this.muteMembersCallback = callback;
        JSONObject object = new JSONObject();
        object.put("groupId", groupId);
        EnvelopeMessage request = new EnvelopeMessage("group", "mutedList", object);
        clientSocket.send(request);
    }

    private void initSearchResultList() {
        searchResultList.setCellFactory(listView -> new ListCell<>() {
            private HBox content;
            private Label nameLabel;
            private Button actionButton;

            {
                nameLabel = new Label();
                actionButton = new Button();
                actionButton.setStyle("-fx-cursor: hand;");


                HBox.setHgrow(nameLabel, Priority.ALWAYS);
                nameLabel.setMaxWidth(Double.MAX_VALUE);

                nameLabel.setStyle("-fx-font-size: 14px; -fx-padding: 5 0 5 10;");
                actionButton.setStyle("-fx-cursor: hand; -fx-background-radius: 5; -fx-font-size: 13px;");

                content = new HBox(10, nameLabel, actionButton);
                content.setAlignment(Pos.CENTER_LEFT);
            }

            @Override
            protected void updateItem(Object item, boolean empty) {
                super.updateItem(item, empty);
                if (empty || item == null) {
                    setGraphic(null);
                    return;
                }

                if (item instanceof FriendShipBody friend) {
                    nameLabel.setText("[好友] " + ((friend.getUser2Name().equals(user.getName()) ? friend.getUser1Name() : friend.getUser2Name())));

                    switch (friend.getStatus()) {
                        case -1 -> {
                            actionButton.setText("添加");
                            actionButton.setDisable(false);
                            actionButton.setOnAction(e -> {
                                sendAddFriendRequest(friend.getUser2Id().equals(user.getId()) ? friend.getUser1Id() : friend.getUser2Id(), friend.getUser2Name().equals(user.getName()) ? friend.getUser1Name() : friend.getUser2Name());
                                friend.setStatus(0);
                                updateItem(friend, false);
                            });
                        }
                        case 0 -> {
                            if (friend.getUser1Id().equals(user.getId())) {
                                actionButton.setText("取消申请");
                                actionButton.setDisable(false);
                                actionButton.setOnAction(e -> {
                                    sendCancelRequest(friend.getUser2Id(), friend.getUser2Name());
                                    friend.setStatus(-1);
                                    updateItem(friend, false);
                                });
                            }
                        }
                        case 1 -> {
                            actionButton.setText("已添加");
                            actionButton.setDisable(true);
                        }
                        case 2 -> {
                            if (Objects.equals(friend.getUser1Id(), user.getId())) {
                                actionButton.setText("取消拉黑");
                                actionButton.setDisable(false);
                                actionButton.setOnAction(e -> {
                                    sendUnblockRequest(friend.getUser2Id(), friend.getUser2Name());
                                    friend.setStatus(-1);
                                    updateItem(friend, false);
                                });
                            } else {
                                actionButton.setText("已被拉黑");
                                actionButton.setDisable(false);
                            }
                        }
                    }
                } else if (item instanceof SearchResultGroupBody group) {
                    nameLabel.setText("[群聊] " + group.getName());

                    switch (group.getStatus()) {
                        case -1 -> {
                            actionButton.setText("申请加入");
                            actionButton.setDisable(false);
                            actionButton.setOnAction(e -> {
                                sendJoinGroupRequest(group.getId(), group.getName());
                                group.setStatus(0);
                                updateItem(group, false);
                            });
                        }
                        case 0 -> {
                            actionButton.setText("取消申请");
                            actionButton.setDisable(false);
                            actionButton.setOnAction(e -> {
                                sendCancelJoinGroupRequest(group.getId(), group.getName());
                                group.setStatus(-1);
                                updateItem(group, false);
                            });
                        }
                        case 1 -> {
                            actionButton.setText("已加入");
                            actionButton.setDisable(true);
                        }
                        case 2 -> {
                            actionButton.setText("你是群主");
                            actionButton.setDisable(true);
                        }
                    }
                } else {
                    setGraphic(null);
                    return;
                }
                setGraphic(content);
            }
        });
    }

    public void initNotificationList() {
        notificationList.setCellFactory(param -> new ListCell<>() {
            private final Label nameLabel = new Label();
            private final Button acceptBtn = new Button("通过");
            private final Button rejectBtn = new Button("拒绝");
            private final HBox hbox = new HBox(10);

            {
                hbox.setAlignment(Pos.CENTER_LEFT);
                HBox.setHgrow(nameLabel, Priority.ALWAYS);
                hbox.getChildren().addAll(nameLabel, acceptBtn, rejectBtn);

                acceptBtn.setStyle("-fx-background-color: #4CAF50; -fx-text-fill: white;");
                rejectBtn.setStyle("-fx-background-color: #f44336; -fx-text-fill: white;");
            }

            @Override
            protected void updateItem(NotificationBody item, boolean empty) {
                super.updateItem(item, empty);
                if (empty || item == null) {
                    setGraphic(null);
                } else {

                    if ("friend".equals(item.getType())) {
                        nameLabel.setText("好友申请来自：" + item.getFromName());

                        acceptBtn.setOnAction(event -> {
                            handleFriendRequest(item, true); // true = 接受
                        });

                        rejectBtn.setOnAction(event -> {
                            handleFriendRequest(item, false); // false = 拒绝
                        });

                        setGraphic(hbox);
                    } else if ("group".equals(item.getType())) {
                        nameLabel.setText(item.getFromName() + " 申请加入群聊「" + item.getGroupName() + "」");
                        acceptBtn.setOnAction(event -> {
                            handleGroupRequest(item, true); // true = 通过
                        });

                        rejectBtn.setOnAction(event -> {
                            handleGroupRequest(item, false); // false = 拒绝
                        });
                        setGraphic(hbox);
                    } else {
                        // 其他类型占位逻辑
                        nameLabel.setText("未知通知类型：" + item.getType());
                        hbox.getChildren().setAll(nameLabel); // 不显示按钮
                        setGraphic(hbox);
                    }
                }
            }
        });
    }

    private void handleGroupRequest(NotificationBody item, boolean accept) {
        JSONObject json = new JSONObject();
        json.put("fromId", item.getFromId());
        json.put("groupId", item.getToGroupId());
        json.put("accept", accept);
        EnvelopeMessage msg = new EnvelopeMessage("group", "response", json);
        clientSocket.send(msg);
        notificationList.getItems().remove(item);
    }

    private void handleFriendRequest(NotificationBody noti, Boolean accept) {
        JSONObject json = new JSONObject();
        json.put("fromId", noti.getFromId());
        json.put("toId", noti.getToUserId());
        json.put("accept", accept); // true通过，false拒绝
        EnvelopeMessage msg = new EnvelopeMessage("friend", "response", json);
        clientSocket.send(msg);
        notificationList.getItems().remove(noti);
    }

    private void sendUnblockRequest(Integer FriendId, String user2Name) {
        JSONObject object = new JSONObject();
        object.put("friendId", FriendId);
        object.put("friendName", user2Name);
        object.put("userId", user.getId());
        object.put("userName", user.getName());
        EnvelopeMessage request = new EnvelopeMessage("friend", "blockCancel", object);
        clientSocket.send(request);
    }

    private void sendCancelRequest(Integer friendId, String friendName) {
        JSONObject object = new JSONObject();
        object.put("toFriendId", friendId);//搜到的人的信息
        object.put("toFriendName", friendName);
        object.put("fromId", user.getId());//发起人的信息
        object.put("fromName", user.getName());
        EnvelopeMessage request = new EnvelopeMessage("friend", "requestCancel", object);
        clientSocket.send(request);

    }

    private void sendAddFriendRequest(Integer FriendId, String FriendName) {
        JSONObject object = new JSONObject();
        object.put("toFriendId", FriendId);//搜到的人的信息
        object.put("toFriendName", FriendName);
        object.put("fromId", user.getId());//发起人的信息
        object.put("fromName", user.getName());
        EnvelopeMessage request = new EnvelopeMessage("friend", "request", object);
        clientSocket.send(request);
    }

    private void sendJoinGroupRequest(Integer groupId, String groupName) {
        JSONObject object = new JSONObject();
        object.put("groupId", groupId);
        object.put("groupName", groupName);
        object.put("userId", user.getId());
        EnvelopeMessage request = new EnvelopeMessage("group", "request", object);
        clientSocket.send(request);
    }

    private void sendCancelJoinGroupRequest(Integer groupId, String groupName) {
        JSONObject object = new JSONObject();
        object.put("groupId", groupId);
        object.put("groupName", groupName);
        object.put("userId", user.getId());
        EnvelopeMessage request = new EnvelopeMessage("group", "requestCancel", object);
        clientSocket.send(request);
    }

    private void switchConversation(FriendShipBody friend, boolean isGroup) {
        String target = friend.getUser1Name().equals(user.getName()) ? friend.getUser2Name() : friend.getUser1Name();
        this.currentChatTarget = target;
        this.isCurrentChatGroup = false;
        chatTitle.setText("与 " + target + " 的私聊");

        messageContainer.getChildren().clear();
        chatHistories.putIfAbsent(target, new VBox(5));

        JSONObject body = new JSONObject();
        body.put("userId", user.getId());
        body.put("friendName", target);
        body.put("friendId", friend.getUser1Id().equals(user.getId()) ? friend.getUser2Id() : friend.getUser1Id());

        EnvelopeMessage request = new EnvelopeMessage("history", "private", body);
        clientSocket.send(request);
    }

    private void switchConversation(GroupShipBody group) {
        this.currentChatTarget = group.getGroupName();
        this.isCurrentChatGroup = true;
        chatTitle.setText("[群聊] " + group.getGroupName());

        messageContainer.getChildren().clear();
        chatHistories.putIfAbsent(group.getGroupName(), new VBox(5));

        JSONObject body = new JSONObject();
        body.put("userId", user.getId());
        body.put("groupId", group.getGroupId());
        body.put("groupName", group.getGroupName());

        EnvelopeMessage request = new EnvelopeMessage("history", "group", body);
        clientSocket.send(request);
    }

    @FXML
    public void onSendMessage() {
        String msg = inputField.getText().trim();
        if (msg.isEmpty() || currentChatTarget == null) return;

        //addMessageBubbleWithTime(user.getName(), msg, LocalDateTime.now().toString(), true, messageContainer);

        JSONObject body = new JSONObject();
        body.put("senderId", user.getId());
        body.put("senderName", user.getName());
        body.put("message", msg);
        body.put("sendTime", LocalDateTime.now());
        body.put("messageType", "text");
        EnvelopeMessage sendMsg;

        if (isCurrentChatGroup) {
            GroupShipBody group = groupList.getSelectionModel().getSelectedItem();
            if (group == null) return;
            if (group.getRole() == -1) {
                Tooltip tooltip = new Tooltip("你已被禁言，暂时无法发言");
                tooltip.setAutoHide(true);
                tooltip.show(inputField.getScene().getWindow());
                return;
            }
            body.put("groupId", group.getGroupId());
            body.put("groupName", group.getGroupName());
            sendMsg = new EnvelopeMessage("chat", "group", body);

        } else {
            FriendShipBody friend = friendList.getSelectionModel().getSelectedItem();
            if (friend == null) return;

            Integer receiverId = user.getId().equals(friend.getUser1Id()) ? friend.getUser2Id() : friend.getUser1Id();
            String receiverName = user.getName().equals(friend.getUser1Name()) ? friend.getUser2Name() : friend.getUser1Name();
            body.put("receiverId", receiverId);
            body.put("receiverName", receiverName);
            sendMsg = new EnvelopeMessage("chat", "private", body);
        }
        addMessageBubbleWithTime(user.getName(), msg, LocalDateTime.now().toString(), true, messageContainer);
        clientSocket.send(sendMsg);
        inputField.clear();
    }

    @FXML
    public void onSendFile() {

        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("选择文件");
        File selectedFile = fileChooser.showOpenDialog(inputField.getScene().getWindow());

        if (selectedFile != null) {
            if (isCurrentChatGroup) {
                sendGroupFile(selectedFile);
            } else {
                sendFile(selectedFile);
            }
        }
    }

    private void sendFile(File file) {
        FriendShipBody friend = friendList.getSelectionModel().getSelectedItem();
        if (friend == null) return;

        long fileSize = file.length();
        String fileUUID = UUID.randomUUID().toString();
        int totalChunks = (int) Math.ceil((double) fileSize / CHUNK_SIZE);
        Integer receiverId = user.getId().equals(friend.getUser1Id()) ? friend.getUser2Id() : friend.getUser1Id();
        String receiverName = user.getName().equals(friend.getUser1Name()) ? friend.getUser2Name() : friend.getUser1Name();

        try (InputStream input = new FileInputStream(file)) {
            byte[] buffer = new byte[CHUNK_SIZE];
            int bytesRead;
            int chunkIndex = 0;

            while ((bytesRead = input.read(buffer)) != -1) {
                byte[] chunkData = Arrays.copyOf(buffer, bytesRead);
                JSONObject body = new JSONObject();
                body.put("senderId", user.getId());
                body.put("senderName", user.getName());
                body.put("receiverId", receiverId);
                body.put("receiverName", receiverName);
                body.put("fileName", file.getName());
                body.put("fileUUID", fileUUID);
                body.put("chunkIndex", chunkIndex);
                body.put("totalChunks", totalChunks);
                body.put("chunkSize", bytesRead);
                body.put("fileChunk", Base64.getEncoder().encodeToString(chunkData));
                body.put("messageType", "fileChunk");
                body.put("sendTime", LocalDateTime.now().toString());

                EnvelopeMessage msg = new EnvelopeMessage("chat", "private", body);
                clientSocket.send(msg);

                chunkIndex++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void sendGroupFile(File file) {
        GroupShipBody group = groupList.getSelectionModel().getSelectedItem();
        if (group == null) return;
        if (group.getRole() == -1) {
            Tooltip tooltip = new Tooltip("你已被禁言，暂时无法发言");
            tooltip.setAutoHide(true);
            tooltip.show(inputField.getScene().getWindow());
            return;
        }
        long fileSize = file.length();
        String fileUUID = UUID.randomUUID().toString();
        int totalChunks = (int) Math.ceil((double) fileSize / CHUNK_SIZE);
        Integer groupId = group.getGroupId();
        String groupName = group.getGroupName();

        try (InputStream input = new FileInputStream(file)) {
            byte[] buffer = new byte[CHUNK_SIZE];
            int bytesRead;
            int chunkIndex = 0;

            while ((bytesRead = input.read(buffer)) != -1) {
                byte[] chunkData = Arrays.copyOf(buffer, bytesRead);
                JSONObject body = new JSONObject();
                body.put("senderId", user.getId());
                body.put("senderName", user.getName());
                body.put("groupName", groupName);
                body.put("groupId", groupId);
                body.put("fileName", file.getName());
                body.put("fileUUID", fileUUID);
                body.put("chunkIndex", chunkIndex);
                body.put("totalChunks", totalChunks);
                body.put("chunkSize", bytesRead);
                body.put("fileChunk", Base64.getEncoder().encodeToString(chunkData));
                body.put("messageType", "fileChunk");
                body.put("sendTime", LocalDateTime.now().toString());

                EnvelopeMessage msg = new EnvelopeMessage("chat", "group", body);
                clientSocket.send(msg);

                chunkIndex++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private void addMessageBubbleWithTime(String sender, String content, String time, boolean isSelf, VBox targetBox) {
        Label bubble = new Label((sender.equals(user.getName()) ? "我" : sender) + ": " + content);

        bubble.setWrapText(true);
        bubble.setStyle("-fx-background-color: " + (isSelf ? "#DCF8C6" : "#FFFFFF") + "; -fx-padding: 5 10; -fx-background-radius: 10; -fx-border-radius: 10;");
        HBox hbox = new HBox(bubble);
        hbox.setMaxWidth(Double.MAX_VALUE);
        hbox.setSpacing(5);
        hbox.setStyle("-fx-padding: 2 0 2 0;");
        hbox.setAlignment(isSelf ? Pos.CENTER_RIGHT : Pos.CENTER_LEFT);

        // 时间 label
        Label timeLabel = new Label("🕓 " + time);
        timeLabel.setStyle("-fx-font-size: 10px; -fx-text-fill: gray;");
        HBox timeBox = new HBox(timeLabel);
        timeBox.setMaxWidth(Double.MAX_VALUE);
        timeBox.setAlignment(isSelf ? Pos.CENTER_RIGHT : Pos.CENTER_LEFT);

        // 添加到聊天框
        targetBox.getChildren().addAll(hbox, timeBox);
    }

    private void addFileMessageBubble(String sender, String fileName, String filePath, String time, boolean isSelf, VBox targetBox) {
        Node contentNode;

        if (isImageFile(fileName)) {
            File imageFile = new File(filePath);
            if (imageFile.exists()) {
                Image image = new Image(imageFile.toURI().toString(), 200, 200, true, true);
                ImageView imageView = new ImageView(image);
                imageView.setPreserveRatio(true);
                imageView.setFitWidth(200);
                imageView.setOnMouseClicked(e -> {
                    try {
                        Desktop.getDesktop().open(imageFile);
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                });
                contentNode = imageView;
            } else {
                contentNode = new Label((sender.equals(user.getName()) ? "我" : sender) + ": [图片文件丢失] " + fileName);
            }
        } else {
            Hyperlink fileLink = new Hyperlink((sender.equals(user.getName()) ? "我" : sender) + ": [文件] " + fileName);
            fileLink.setOnAction(e -> {
                try {
                    Desktop.getDesktop().open(new File(filePath));
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            });
            fileLink.setStyle("-fx-background-color: " + (isSelf ? "#D2F2FC" : "rgba(14,222,222,0.71)") + "; -fx-padding: 5 10; -fx-background-radius: 10;");
            contentNode = fileLink;
        }

        HBox hbox = new HBox(contentNode);
        hbox.setMaxWidth(Double.MAX_VALUE);
        hbox.setSpacing(5);
        hbox.setStyle("-fx-padding: 2 0 2 0;");
        hbox.setAlignment(isSelf ? Pos.CENTER_RIGHT : Pos.CENTER_LEFT);

        Label timeLabel = new Label("🕓 " + time);
        timeLabel.setStyle("-fx-font-size: 10px; -fx-text-fill: gray;");
        HBox timeBox = new HBox(timeLabel);
        timeBox.setMaxWidth(Double.MAX_VALUE);
        timeBox.setAlignment(isSelf ? Pos.CENTER_RIGHT : Pos.CENTER_LEFT);

        targetBox.getChildren().addAll(hbox, timeBox);
    }


    private boolean isImageFile(String fileName) {
        String lower = fileName.toLowerCase();
        return lower.endsWith(".jpg") || lower.endsWith(".jpeg") || lower.endsWith(".png") || lower.endsWith(".gif") || lower.endsWith(".bmp");
    }

    private void initMessageListener() {
        clientSocket.setMessageListener(msg -> {
            Platform.runLater(() -> {
                switch (msg.getModule()) {
                    case "chat":
                        handleChatMessage(msg);
                        break;
                    case "history":
                        handleHistoryMessage(msg);
                        break;
                    case "friend":
                        handleFriendMessage(msg);
                        break;
                    case "group":
                        handleGroupMessage(msg);
                        break;
                    case "notification":
                        handleNotification(msg);
                    case "system":
                        handleSystemMessage(msg);
                    default:
                        break;
                }
            });
        });
    }


    private void handleHistoryMessage(EnvelopeMessage msg) {
        JSONObject body = msg.getBody();
        String targetName = isCurrentChatGroup ? body.getString("groupName") : body.getString("friendName");

        chatHistories.putIfAbsent(targetName, new VBox(5));
        VBox historyBox = chatHistories.get(targetName);
        historyBox.getChildren().clear();

        JSONArray messages = body.getJSONArray("messages");
        if (messages != null) {
            for (Object obj : messages) {
                JSONObject message = (JSONObject) obj;

                String sender = message.getString("senderName");
                String time = message.getString("sendTime");
                boolean isSelf = sender.equals(user.getName());

                String type = message.getOrDefault("messageType", "text").toString();

                switch (type) {
                    case "file":
                    case "image": {
                        String fileName = message.getString("fileName");
                        String filePath = message.getString("message");

                        File file = new File(filePath);
                        if (file.exists()) {
                            addFileMessageBubble(sender, fileName, filePath, time, isSelf, historyBox);
                        } else {
                            addMessageBubbleWithTime(sender, "[文件已丢失] " + fileName, time, isSelf, historyBox);
                        }
                        break;
                    }
                    case "text":
                    default: {
                        String content = message.getString("message");
                        addMessageBubbleWithTime(sender, content, time, isSelf, historyBox);
                        break;
                    }
                }
            }
        }

        if (targetName.equals(currentChatTarget)) {
            messageContainer.getChildren().setAll(historyBox.getChildren());
        }
    }


    private void handleChatMessage(EnvelopeMessage msg) {
        JSONObject body = msg.getBody();
        String senderName = body.getString("senderName");
        String content = body.getString("message");
        String time = body.getString("sendTime");
        String type = body.getString("messageType");

        boolean isSelf = body.getInteger("senderId").equals(user.getId());

        if ("group".equals(msg.getAction())) {
            String groupName = body.getString("groupName");
            chatHistories.putIfAbsent(groupName, new VBox(5));

            if (groupName.equals(currentChatTarget)) {
                if (!isSelf) {
                    handleMessageByType(type, senderName, content, time, isSelf, messageContainer);
                }
            } else {
                MessageNotificationDialog.showMessage(
                        (Stage) inputField.getScene().getWindow(),
                        "📢 群 " + groupName + " 有新消息"
                );
            }

        } else if ("private".equals(msg.getAction())) {
            String targetName = senderName;
            chatHistories.putIfAbsent(targetName, new VBox(5));

            if (targetName.equals(currentChatTarget)) {
                handleMessageByType(type, senderName, content, time, isSelf, messageContainer);
            } else {
                MessageNotificationDialog.showMessage(
                        (Stage) inputField.getScene().getWindow(),
                        "💬 " + senderName + " 发来新消息"
                );
            }
        }
    }

    private void handleMessageByType(String type, String sender, String content, String time, boolean isSelf, VBox container) {
        switch (type) {
            case "text":
                addMessageBubbleWithTime(sender, content, time, isSelf, container);
                break;
            case "file":
            case "image":
                File file = new File(content);
                addFileMessageBubble(sender, file.getName(), file.getAbsolutePath(), time, isSelf, container);
                break;
            default:
                addMessageBubbleWithTime(sender, "[未知类型消息]", time, isSelf, container);
                break;
        }
    }

    private void handleFriendMessage(EnvelopeMessage msg) {
        if ("list".equals(msg.getAction())) {
            JSONArray arr = msg.getBody().getJSONArray("friends");
            if (arr != null) {
                List<FriendShipBody> friends = arr.toJavaList(FriendShipBody.class);
                friendList.getItems().setAll(friends);
            } else {
                friendList.getItems().clear();
            }
        } else if ("searchFriends".equals(msg.getAction())) {
            JSONArray arr = msg.getBody().getJSONArray("list");
            List<FriendShipBody> friendList = new ArrayList<>();
            for (int i = 0; i < arr.size(); i++) {
                JSONObject obj = arr.getJSONObject(i);
                friendList.add(new FriendShipBody(
                        obj.getInteger("user1Id"),
                        obj.getString("user1Name"),
                        obj.getInteger("user2Id"),
                        obj.getString("user2Name"),
                        obj.getInteger("status")
                ));
            }
            searchResultList.getItems().setAll(friendList);

        }
    }

    private void handleGroupMessage(EnvelopeMessage msg) {
        switch (msg.getAction()) {
            case "list" -> {
                try {
                    JSONArray arr = msg.getBody().getJSONArray("groups");
                    List<GroupShipBody> groups = arr.toJavaList(GroupShipBody.class);
                    Platform.runLater(() -> groupList.getItems().setAll(groups));
                } catch (Exception e) {
                    System.err.println("解析群列表失败: " + e.getMessage());
                }
            }

            case "create_result" -> {
                boolean success = msg.getBody().getBoolean("success");
                if (success) {
                    // 自动刷新群列表
                    JSONObject body = new JSONObject();
                    body.put("userId", user.getId());
                    EnvelopeMessage groupReq = new EnvelopeMessage("group", "list", body);
                    clientSocket.send(groupReq);
                } else {
                    Platform.runLater(() -> showAlert("创建群聊失败！"));
                }
            }

            case "searchGroups" -> {
                try {
                    JSONArray arr = msg.getBody().getJSONArray("resultsGroups");
                    List<SearchResultGroupBody> groups = arr.toJavaList(SearchResultGroupBody.class);
                    Platform.runLater(() -> searchResultList.getItems().setAll(groups));
                } catch (Exception e) {
                    System.err.println("解析群聊搜索结果失败: " + e.getMessage());
                }
            }

            case "mutedList" -> {
                JSONArray arr = msg.getBody().getJSONArray("mutedList");
                mutedMembers = arr.toJavaList(String.class);
                if (muteMembersCallback != null) {
                    muteMembersCallback.accept(mutedMembers);
                    muteMembersCallback = null;
                }
            }
            default -> System.out.println("未知 group 事件: " + msg.getAction());
        }
    }

    private void handleNotification(EnvelopeMessage msg) {
        switch (msg.getAction()) {
            case "list" -> {
                try {
                    JSONArray arr = msg.getBody().getJSONArray("requests");
                    List<NotificationBody> requests = arr.toJavaList(NotificationBody.class);
                    Platform.runLater(() -> notificationList.getItems().setAll(requests));
                    //   System.out.println(notificationList);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("解析请求列表失败");
                }
            }

        }

    }

    private void handleSystemMessage(EnvelopeMessage msg) {
        switch (msg.getAction()) {
            case "kickOut" -> {
                Platform.runLater(() -> {
                    Alert alert = new Alert(Alert.AlertType.INFORMATION);
                    alert.setTitle("系统通知");
                    alert.setHeaderText("您已被服务器踢下线");
                    alert.setContentText("可能是长时间未操作或被管理员移除。");
                    alert.showAndWait();
                    clientSocket.close();
                    Platform.exit();//关闭前端javafx界面
                });
            }
            default -> System.out.println("未知系统消息");

        }

    }

    @FXML
    private void onCreateGroup() {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/client/ui/create_group_dialog.fxml"));
            Parent root = loader.load();

            CreateGroupDialogController controller = loader.getController();
            controller.setOnGroupCreateListener(groupName -> {
                Integer managerId = user.getId();
                JSONObject object = new JSONObject();
                object.put("groupName", groupName);
                object.put("managerId", managerId);
                EnvelopeMessage request = new EnvelopeMessage("group", "create", object);
                clientSocket.send(request);

            });

            Stage dialogStage = new Stage();
            dialogStage.setTitle("创建群聊");
            dialogStage.initModality(Modality.APPLICATION_MODAL);
            dialogStage.setScene(new Scene(root));
            dialogStage.show();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void loadFriendAndGroupList() {
        JSONObject body = new JSONObject();
        body.put("userId", user.getId());

        EnvelopeMessage friendReq = new EnvelopeMessage("friend", "list", body);
        //  EnvelopeMessage groupReq = new EnvelopeMessage("group", "list", body);

        clientSocket.send(friendReq);
        //  clientSocket.send(groupReq);
    }

    @FXML
    public void switchToFriendView(ActionEvent e) {
        friendListView.setVisible(true);
        groupListView.setVisible(false);
        searchView.setVisible(false);
        chatView.setVisible(true);
        notificationView.setVisible(false);
        JSONObject body = new JSONObject();
        body.put("userId", user.getId());
        EnvelopeMessage friendReq = new EnvelopeMessage("friend", "list", body);
        clientSocket.send(friendReq);

    }

    @FXML
    public void switchToGroupView(ActionEvent e) {
        friendListView.setVisible(false);
        groupListView.setVisible(true);
        searchView.setVisible(false);
        chatView.setVisible(true);
        notificationView.setVisible(false);
        JSONObject body = new JSONObject();
        body.put("userId", user.getId());
        EnvelopeMessage groupReq = new EnvelopeMessage("group", "list", body);
        clientSocket.send(groupReq);
    }

    @FXML
    public void returnToChatView(ActionEvent e) {
        searchView.setVisible(false);
        notificationView.setVisible(false);
        chatView.setVisible(true);
        searchInputField.clear();
    }

    private void showAlert(String message) {
        Alert alert = new Alert(Alert.AlertType.WARNING);
        alert.setTitle("提示");
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }


    @FXML
    private void onLogout() {
        if (ConfirmDialog.show("确认退出", "你确定要退出登录吗？")) {
            JSONObject object = new JSONObject();
            object.put("userId", user.getId());
            EnvelopeMessage msg = new EnvelopeMessage("user", "logout", object);
            clientSocket.send(msg);

            // 延迟退出
            new Thread(() -> {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                clientSocket.close();
                Platform.exit(); // 关闭 JavaFX 应用
            }).start();
        }
    }

    @FXML
    public void showSearchView(ActionEvent e) {
        searchView.setVisible(true);
        chatView.setVisible(false);
        notificationView.setVisible(false);
        searchInputField.clear(); // 每次清空输入框
        searchResultList.getItems().clear(); // 清空旧的搜索结果
        if (e.getSource() == friendSearchBtn) {
            searchTitle.setText("搜索添加新朋友");
            searchMode = "friend";
        } else if (e.getSource() == groupSearchBtn) {
            searchTitle.setText("搜索群聊");
            searchMode = "group";
        }
    }

    private void sendSearchRequest(String keyword) {
        if (keyword == null || keyword.isEmpty()) return;

        JSONObject object = new JSONObject();
        object.put("userId", user.getId());
        object.put("userName", user.getName());
        if ("friend".equals(searchMode)) {
            object.put("newFriend", keyword);
            EnvelopeMessage back = new EnvelopeMessage("friend", "search", object);
            clientSocket.send(back);
        } else if ("group".equals(searchMode)) {
            object.put("groupName", keyword);
            EnvelopeMessage back = new EnvelopeMessage("group", "search", object);
            clientSocket.send(back);
        }
    }

    @FXML
    private void switchToNotificationView() {
        notificationView.setVisible(true);
        chatView.setVisible(false);
        searchView.setVisible(false);
        JSONObject object = new JSONObject();
        object.put("userId", user.getId());
        EnvelopeMessage msg = new EnvelopeMessage("notification", "list", object);
        clientSocket.send(msg);
    }
}
